import neko.net.Socket;
import format.amf.Value;
import format.flv.Data;
import hxvid.Client;
import hxvid.Rtmp;
import hxvid.Commands;
import hxvid.Data;
import hxvid.Server;
import hxvid.Logger;
import hxvid.SharedObject;
import hxvid.IApplication;
import hxvid.events.IEvent;
import hxvid.events.ApplicationEvent;
import hxvid.events.ConnectionEvent;
import hxvid.events.StreamEvent;
import hxvid.events.ServerEvent;
import hxvid.events.SharedObjectEvent;

class Application implements IApplication
{
	private var server:Server;
	public var config:ApplicationConfig;
	private var admin:Client;
	var logger:Logger;
	public function new(server:Server, config:ApplicationConfig)
	{
		this.server = server;
		this.config = config;
		this.admin = null;
		logger = new Logger(config.logFile);
		logger.id = "admin/Application";
		logger.info("started");
		
		server.addEventListener(ApplicationEvent.APP_START, onAppStart);
		server.addEventListener(ApplicationEvent.APP_RELOAD, onAppReload);
		server.addEventListener(ServerEvent.SOCKET_CONNECT, onSocketConnect);
		server.addEventListener(ServerEvent.CLIENT_CONNECT, onClientConnect);
		
		//server.addEventListener(ServerEvent.CLIENT_DISCONNECT, onServerClientDisconnect);
		//server.addEventListener(ServerEvent.SOCKET_DISCONNECT, onSocketDisconnect);
	}
	public function onConnect(admin:Client, obj:ConnectionObject, ?arg:Dynamic=null):Void
	{
		logger.info("client: "+ admin.ip);
		//if(this.admin!=null) return;
		this.admin = admin;
		admin.addCommands(
		[
			["reloadApplication", this.reloadApplication, T.Null, T.String ],
			["getApplications", this.getApplications, T.Null ]
			
		]);
	}
	function onAppStart(event:ApplicationEvent):Void
	{
		var app:IApplication = event.data;
		logger.info("config:" + app.config);
		if(admin!=null && admin.send1!=null)
			admin.send1("onAppStart", app.config);
	}
	function onSocketConnect(event:ServerEvent):Void
	{
		var socket:Socket =  event.data;
		logger.info("s: "+socket.peer().host.toString());
		if(admin!=null)
			admin.send1("onSocketConnect", socket.peer().host.toString());
	}
	function onClientConnect(event:ServerEvent):Void
	{
		var client:Client = event.data.client;
		var obj:ConnectionObject = event.data.obj;
		var arg:Dynamic = event.data.arg;
		if(client!=null)
		{
			if(client.socket!=null)
			{
				logger.info("client: "+client.ip + ", obj:"+obj+", arg:"+arg);
				client.addEventListener(ConnectionEvent.CONNECTED, onClientConnected);
			}
		}
		if(admin!=null)
			admin.send1("onClientConnect", {client:admin.socket.peer().host.toString(), obj:obj, arg:arg});
	}
	function onClientConnected(event:ConnectionEvent):Void
	{
		var client = event.target;
		client.addEventListener(ConnectionEvent.DISCONNECTED, onClientDisconnected);
		
		client.addEventListener(StreamEvent.STREAM_CREATE, onStreamCreate);
		client.addEventListener(StreamEvent.STREAM_DELETE, onStreamDelete);
		client.addEventListener(StreamEvent.STREAM_PUBLISH, onStreamPublish);
		client.addEventListener(StreamEvent.STREAM_PLAY, onStreamPlay);
		client.addEventListener(StreamEvent.STREAM_CLOSE, onStreamClose);
		client.addEventListener(StreamEvent.STREAM_SEEK, onStreamSeek);
		client.addEventListener(StreamEvent.STREAM_PAUSE, onStreamPause);
		client.addEventListener(StreamEvent.STREAM_PAUSE_RAW, onStreamPauseRaw);
		client.addEventListener(StreamEvent.STREAM_AUDIO_RECEIVE, onStreamAudioReceive);
		client.addEventListener(StreamEvent.STREAM_VIDEO_RECEIVE, onStreamVideoReceive);
		
		client.addEventListener(SharedObjectEvent.SUBSCRIBE, onSharedObjectSubscribe);
		//client.addEventListener(SharedObjectEvent.UNSUBSCRIBE, onSharedObjectUnSubscribe);
		
		logger.info("client: "+client.socket.peer().host.toString());
		if(admin!=null)admin.send1("onClientConnected", client.socket.peer().host.toString());
	}
	function onClientDisconnected(event:ConnectionEvent):Void
	{
		//trace(event);
		//var client = event.target;
		//client.cleanup();
		logger.info("");
		//if(client==admin)
			//admin=null;
		//if(admin!=null)admin.send1("onClientDisconnected", client.ip);
	}
	function onStreamCreate(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamCreate", client.ip);
	}
	function onStreamDelete(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamDelete", client.ip);
	}
	function onStreamPublish(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamPublish", client.ip);
	}
	function onStreamPlay(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamPlay", client.ip);
	}
	function onStreamClose(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamClose", client.ip);
	}
	function onStreamSeek(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamSeek", client.ip);
	}
	function onStreamPause(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamPause", client.ip);
	}
	function onStreamPauseRaw(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamRawPause", client.ip);
	}
	function onStreamAudioReceive(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamAudioReceive", client.ip);
	}
	function onStreamVideoReceive(event:StreamEvent):Void
	{
		var info = event.data.info;
		var client = info.c;
		logger.info("client: " + client.ip+", stream:"+event.data.name);
		if(admin!=null)admin.send1("onStreamVideoReceive", client.ip);
	}
	
	function onSharedObjectSubscribe(event:SharedObjectEvent):Void
	{
		var info = event.data;
		var client = event.data;
		logger.info("client: " + client.ip+", so:"+info);
		if(admin!=null)admin.send1("onSharedObjectSubscribe", info);
	}
	
	function onSharedObjectUnSubscribe(event:SharedObjectEvent):Void
	{
		var info = event.data;
		var client = event.data;
		logger.info("client: " + client.ip+", so:"+info);
		if(admin!=null)admin.send1("onSharedObjectUnSubscribe", info);
	}
	function onAppReload(event:ApplicationEvent):Void
	{
		var info:ApplicationInfo = event.data;
		logger.info("name: " + info.name + ", version:"+info.version);
		if(admin!=null)admin.send0("onAppReload");
	}
	function reloadApplication(cinf:CommandInfos, _ ,appName:String):Void
	{
		logger.info("name: "+appName);
		server.reloadApplication(appName);
	}
	function getApplications(cinf:CommandInfos, _ ):Void
	{
		logger.info("client:"+cinf.c.ip);
		var client:Client = cinf.c;
		var applications = [];
		for (info in server.applications)
		{
			var clients = [];
			for(c in info.clients)
			{
				clients.push(
				{
					id:c.id,
					name:c.name,
					ip:c.socket.peer().host.toString(),
				});
			}
			var streams = [];
			for(s in info.sharedStreams)
			{
				streams.push(
				{
					id:s.id,
					name:s.name
				});
			}
			var objects = [];
			for(o in info.sharedObjects)
			{
				objects.push(
				{
					name:o.name
				});
			}
			applications.push(
			{
				name:info.name,
				version:info.version,
				config:info.config,
				clients:clients,
				streams:streams,
				objects:objects
			});
		}
		client.sendResult(cinf, applications);
	}
	/*
	data:applications:
	[
		{
			name:info.name,
			version:info.version,
			config:{name, streamsDir, soDir, logFile, isRoom, version}
			clients:[ {id, name, ip}]
			streams:[ {id, name}]
			streams:[ {id, name}]
		}
	]
	*/
	
	/*
	function login(cinf:CommandInfos, _ ,name:String):Void
	{	
		trace("client logs in with name:"+ name);
		var client:Client = cinf.c;
		if(!checkUserName(name))
		{
			client.sendResult(cinf, false);
		}
		else
		{
			client.sendResult(cinf, true);
			client.id = clientID++;
			client.name = name;
			for (c in clients)
			{
				c.send2("userJoin", Date.now(), {id:client.id, name:client.name});
			}
		}
	}
	function textInput(cinf:CommandInfos, _ , text:String):Void
	{
		var client:Client = cinf.c;
		for (c in clients)
		{
			c.send3("textInput", Date.now(), {id:client.id, name:client.name}, text);
		}
	}
	function getUsers(cinf:CommandInfos, _ ):Void
	{
		var client:Client = cinf.c;
		var out:Array<User> =[];
		for (c in clients)
			if(c.id!=null)
				out.push({id:c.id, name:c.name});
		client.sendResult(cinf, out);
	}
	function isTyping(cinf:CommandInfos, _ ):Void
	{
		var client:Client = cinf.c;
		for (c in clients)
		{
			c.send1("isTyping", {id:client.id, name:client.name});
		}
	}
	function checkUserName(name:String):Bool
	{
		for (c in clients)
			if(c.name==name)
				return false;
		return true;
	}
	public function onClientDisconnect(event:ClientEvent)
	{
		var client = event.target;
		trace("onClientDisconnect: " +client.id+","+client.name);
		var user = {id:client.id, name:client.name};
		for (i in 0...clients.length)
		{
			if(clients[i]==client)
			{
				clients.splice(i,1);
				break;
			}
		}
		for (c in clients)
		{
			c.send2("userLeave", Date.now(), user);
		}
	}
	*/
}